/*---------------------------------------
* Author:ZJ
* createDate:Tuesday, August 07, 2012
* Description:
*
------------------------------------------*/

#include "StdAfx.h"
#include "server.hpp"

namespace fly {

	namespace jld{

		namespace server {

			server::server(handler* handler, const std::string& addr,const std::string& port)
				:signals_(is_pool->get_io_service()),
				acceptor_(is_pool->get_io_service()),
				connection_manager_(),
				handler_(handler),
				new_connection_()
			{
				// Register to handle the signals that indicate when the server should exit.
				// It is safe to register for the same signal multiple times in a program,
				// provided all registration for the specified signal is made through Asio.
				signals_.add(SIGINT);
				signals_.add(SIGTERM);
#if defined(SIGQUIT)
				signals_.add(SIGQUIT);
#endif // defined(SIGQUIT)
				signals_.async_wait(boost::bind(&server::clear, this));

				// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
				boost::asio::ip::tcp::resolver resolver(is_pool->get_io_service());
				//address = "::" not only like as "0.0.0.0", but also suport the ip_v6
				//equivalently address = "" or "::" and flag = passive
				boost::asio::ip::tcp::resolver::query query(addr, port);
				ip::tcp::resolver::iterator iter = resolver.resolve(query);
				ip::tcp::resolver::iterator end;
				system::error_code err;
				while (iter != end)
				{
					ip::tcp::endpoint endpoint = *(iter++);
					LOG_PRINTF("Open the endpoint:<%s>:<%d>", endpoint.address().to_string().c_str(), endpoint.port());
					acceptor_.open(endpoint.protocol(), err);
					if (err)
					{
						LOG_WARN("Open falid:", err.message());
						continue;
					}
					acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), err);
					if (err)
					{
						LOG_WARN("Set reuse address option faild:", err.message());
						acceptor_.close();
						continue;
					}
					acceptor_.bind(endpoint, err);
					if (err)
					{
						LOG_WARN("Bind faild:", err.message());
						acceptor_.close();
						continue;
					}
					if (acceptor_.is_open())
					{
						LOG_INFO("Acceptor is successfully open");
						break;
					}
				}
				
				if (!acceptor_.is_open())
				{
					LOG_ERR("Acceptor fail to be open");
					signals_.cancel();
					return;
				}
				acceptor_.listen(100000, err);
				if (err)
				{
					LOG_ERR("Listen faild:", err.message());
					signals_.cancel();
					return;
				}
				LOG_INFO("Server have bind and listen.");

				srv_ansy_accept();
			}

			void server::run()
			{
				// The io_service::run() call will block until all asynchronous operations
				// have finished. While the server is running, there is always at least one
				// asynchronous operation outstanding: the asynchronous accept call waiting
				// for new incoming connections.
				is_pool->run();
			}

			void server::clear()
			{
				// The server is stopped by cancelling all outstanding asynchronous
				// operations. Once all operations have finished the io_service::run() call
				// will exit.
				acceptor_.close();
				connection_manager_.stop_all();
				is_pool->stop();
			}

			void server::srv_ansy_accept()
			{
				new_connection_.reset(new connection(is_pool->get_io_service(),connection_manager_, handler_));
				acceptor_.async_accept(new_connection_->socket()
					,boost::bind(&server::handle_callback_accept, this,
					boost::asio::placeholders::error));
			}

			void server::handle_callback_accept(const boost::system::error_code& e)
			{
				// Check whether the server was stopped by a signal before this completion
				// handler had a chance to run.
				if (!acceptor_.is_open())
				{
					LOG_T_ERR("Acceptor_ is close.");
					return;
				}

				if(!e)
				{
					connection_manager_.start(new_connection_);
				}	
				else
				{
					LOG_T_ERR(e.message());
				}
				srv_ansy_accept();
			}

		}
	}
}